# -*- coding: utf-8 -*-
import re

from flask import url_for
from sqlalchemy import Column, Integer, String, DateTime
from flask_login import UserMixin, AnonymousUserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from jieba.analyse.analyzer import ChineseAnalyzer

from .exception import ValidationError
from . import db, login_manager


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


class Role(db.Model):
    __tablename__ = "role"
    id = Column(Integer, primary_key=True)
    name = Column(String(255), unique=True)
    create_date = Column(DateTime, default=datetime.now())
    users = db.relationship('User',
                            backref='role',
                            lazy='dynamic',
                            primaryjoin='User.role_id == Role.id')

    @staticmethod
    def insert_roles():
        roles = [
            u"用户",
            u"管理员",
        ]

        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            db.session.add(role)
        db.session.commit()


class Star(db.Model):
    __tablename__ = 'star'
    # id = Column(Integer, primary_key=True)
    user_id = Column(Integer, db.ForeignKey('user.id'), primary_key=True)
    job_id = Column(Integer, db.ForeignKey('job.id'), primary_key=True)
    alarm = Column(db.DateTime)
    status = Column(db.Boolean, default=True)
    create_date = Column(db.DateTime, default=datetime.now)


class UserStatus():
    ACTIVE = 1
    DELETED = 0

    data = {
        ACTIVE: u'激活',
        DELETED: u'删除',
    }

    @staticmethod
    def getAll():
        return [(UserStatus.ACTIVE, u'激活'), (UserStatus.DELETED, u'删除')]

    @staticmethod
    def get(id):
        return UserStatus.data[id]


class User(db.Model, UserMixin):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(64), unique=True)
    password = Column(String(255))
    password_hash = Column(String(128))
    nickname = Column(String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
    status = db.Column(db.Boolean, default=1)
    create_date = Column(DateTime(), default=datetime.now)
    followed = db.relationship('Star',
                               foreign_keys=[Star.user_id],
                               backref=db.backref('follower', lazy='joined'),
                               lazy='dynamic',
                               cascade='all, delete-orphan')

    def __repr__(self):
        return '<User %r>' % (self.username)

    @property
    def status_name(self):
        return UserStatus.get(self.status)

    @property
    def is_active(self):
        return self.status == UserStatus.ACTIVE

    @property
    def is_admin(self):
        return self.role_id == 2

    @property
    def password(self):
        raise ArithmeticError('password is not a readable attribute.')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def confirm(self, token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return False
        if data.get('confirm') != self.id:
            return False
        self.status = True
        db.session.add(self)
        return True

    def generate_auth_token(self, expiration):
        s = Serializer(current_app.config['SECRET_KEY'],
                       expires_in=expiration)
        return s.dumps({'id': self.id})

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return None
        return User.query.get(data['id'])

    def to_json(self):
        json_user = {
            'email': self.username,
            'nickname': self.nickname,
            'role': self.role.name,
            'create_date': self.create_date,
            'stared': [f.job_id for f in self.followed.all()],
            'alarm': [f.job_id for f in self.followed.all() if f.alarm is not None]
        }

        return json_user

    @staticmethod
    def from_json(json_user):
        username = json_user.get('username')
        nickname = json_user.get('nickname')
        password = json_user.get('password')
        if not (username and nickname and password):
            raise ValidationError(u'请填写所以信息。')
        if not re.match(r'\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b', username):
            raise ValidationError(u'邮箱格式不正确。')


        if User.query.filter_by(username=username).first():
            raise ValidationError(u'邮箱已注册。')
        if User.query.filter_by(nickname=nickname).first():
            raise ValidationError(u'昵称已注册。')

        user = User(username=username,
                    nickname=nickname,
                    password=password,
                    status=UserStatus.ACTIVE,
                    role_id=1)

        return user


class Job(db.Model):
    __tablename__ = 'job'
    __searchable__ = ['title', 'content']
    __analyzer__ = ChineseAnalyzer()

    id = Column(Integer, primary_key=True)
    title = Column(String(255))
    content = Column(db.Text)
    url = Column(String(255))
    md5 = Column(String(255))
    source_name = Column(String(255), db.ForeignKey('source.name'))
    tags = Column(String(255))
    open_date = Column(String(255))
    open_date_int = Column(Integer())
    published_date = Column(String(255))
    status = Column(db.Boolean, default=True)
    create_date = Column(db.DateTime, default=datetime.now())
    followers = db.relationship('Star',
                                foreign_keys=[Star.job_id],
                                backref=db.backref('followed', lazy='joined'),
                                lazy='dynamic',
                                cascade='all, delete-orphan')

    def to_json(self):
        json_job = {
            'id': self.id,
            'url': url_for('api.get_job', id=self.id, _external=True),
            'title': self.title,
            'ref_url': self.url,
            'open_date': self.open_date,
            'open_date_int': self.open_date_int,
            'published_date': self.published_date,
            'create_date': self.create_date,
            'tags': self.tags,
            'follower_count': self.followers.count()
        }

        return json_job


class Source(db.Model):
    __tablename__ = 'source'
    name = Column(String(255), primary_key=True)
    title = Column(String(255))
    url = Column(String(255))
    create_date = Column(DateTime, default=datetime.now())
    jobs = db.relationship('Job',
                            backref='source',
                            lazy='dynamic')

    @staticmethod
    def insert_source():
        data = [
            {
                "name": "guet",
                "title": u'桂林电子科技大学毕业生就业网',
                'url': 'http://job.myclub2.com/',
            },
            {
                "name": "glut",
                "title": u'桂林理工大学毕业生就业网',
                'url': 'http://www.doerjob.com/nologin/school.htm',
            },
        ]

        for s in data:
            if Source.query.filter_by(name=s['name']).first():
                continue
            source = Source(
                name=s['name'],
                title=s['title'],
                url=s['url'],
            )
            db.session.add(source)
        db.session.commit()


class Anonymous(AnonymousUserMixin):
    def can(self, permissions):
        return False

